package io.qar.tags.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qar.commons.mybatis.service.impl.CrudServiceImpl;
import io.qar.commons.tools.exception.RenException;
import io.qar.commons.tools.utils.ConvertUtils;
import io.qar.tags.dao.TagsDao;
import io.qar.tags.dto.TagsDTO;
import io.qar.tags.entity.DishTagsEntity;
import io.qar.tags.entity.TagsEntity;
import io.qar.tags.service.TagsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.yaml.snakeyaml.util.ArrayUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 菜单标签
 *
 * @author yyyyjinying 1020066395@qq.com
 * @since 3.0 2024-06-10
 */
@Service
public class TagsServiceImpl extends CrudServiceImpl<TagsDao, TagsEntity, TagsDTO> implements TagsService {
    @Autowired
    private Snowflake snowflake;
    @Override
    public QueryWrapper<TagsEntity> getWrapper(Map<String, Object> params) {
        QueryWrapper<TagsEntity> wrapper = new QueryWrapper<>();


        return wrapper;
    }
    @Override
    public void delete(Long[] tagIds) {
        Long dishId = tagIds[0];
        Long tagId = tagIds[1];
        List<DishTagsEntity> records = baseDao.selectRelationByTag(tagId);
        List<DishTagsEntity> collect = records.stream().filter(item -> !item.getDishId().equals(dishId)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)){
            List<Long> collect1 = collect.stream().map(DishTagsEntity::getDishId).collect(Collectors.toList());
            throw new RenException("该标签已绑定其他菜品，无法删除 " + JSONObject.toJSONString(collect1));
        } else {
            Long[] ids = {tagId};
            super.delete(ids);
        }
    }


    @Override
    public List<TagsDTO> tagByDishId(Long dishId) {
        List<TagsEntity> tagsEntities = baseDao.tagByDishId(dishId, null);
        List<TagsDTO> collect = tagsEntities.stream().map(item -> {
            TagsDTO tagsDTO = ConvertUtils.sourceToTarget(item, TagsDTO.class);
            tagsDTO.setChecked(true);
            tagsDTO.setType("success");
            return tagsDTO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public void saveAndUpdateTag(Long dishId, List<TagsDTO> tagLists) {
        if (CollectionUtils.isEmpty(tagLists)) {
            return;
        }
        List<TagsDTO> updateData = new ArrayList<>();
        List<TagsDTO> insertData = new ArrayList<>();
        for (TagsDTO item : tagLists) {
            if (item != null) { // 增加对item的非空检查
                if (shouldUpdate(item)) { // 使用提取的方法简化逻辑并提高可读性
                    updateData.add(item);
                } else {
                    // 新增生成唯一id
                    item.setTagId(snowflake.nextId());
                    insertData.add(item);
                }
            }
        }

        if (!CollectionUtils.isEmpty(updateData)) {
            super.updateBatchById(ConvertUtils.sourceToTarget(updateData, TagsEntity.class));
        }

        if (!CollectionUtils.isEmpty(insertData)) {
            // 1 新增标签
            List<TagsEntity> tagsEntities = ConvertUtils.sourceToTarget(insertData, TagsEntity.class);
            super.insertBatch(tagsEntities);
        }


        // 根据插入的数据流，筛选出已选中的标签，映射为DishTagsEntity对象集合
        List<DishTagsEntity> dishTagsEntityCollect = tagLists.stream().filter(TagsDTO::getChecked).map(item -> {
            DishTagsEntity dishTagsEntity = new DishTagsEntity();
            dishTagsEntity.setTagId(item.getTagId());
            dishTagsEntity.setDishId(dishId);
            return dishTagsEntity;
        }).collect(Collectors.toList());

        // 收集已存在的菜标签关系，以dishId:tagId为键
//        在计算机科学中，使用哈希表（如Java中的Map）进行查找操作的时间复杂度通常被认为是O(1)，即常数时间。这是因为哈希表通过哈希函数将键映射到数组的一个位置上，理想情况下，每个键都映射到不同的位置，这样查找、插入或删除一个元素只需要定位到该位置，而不需要遍历整个数组。
//        当使用Map存储filteredEntities的结果，并以dish_id和tag_id的组合作为键时，查找时间从线性降低到常数级的原因如下：
//        哈希计算：对于给定的键（这里是dish_id和tag_id的组合），哈希函数会快速计算出一个索引，这个索引指向了存储在Map中的具体位置。
//        直接访问：一旦计算出索引，就可以直接访问该位置上的值，而无需遍历整个Map。即使有冲突（多个键映射到了同一个位置），现代哈希表实现（如HashMap）也会通过链表或红黑树等数据结构来解决冲突，使得查找仍然保持在接近常数的时间内完成。
//        避免全表扫描：与基于数组或列表的线性查找不同，哈希表的查找不会涉及到全表扫描，因此即使Map中存储了大量的元素，查找时间也不会随着元素数量的增加而显著增加。
//        综上所述，使用Map可以将查找时间从依赖于元素数量的线性时间降低到几乎不受元素数量影响的常数时间，从而极大地提高了处理大量数据时的效率。这在需要频繁查找特定元素的场景下尤其重要，例如在处理filteredEntities列表时，使用Map可以避免多次遍历整个列表，从而减少内存消耗和提高处理速度。
//        List<DishTagsEntity> relation = baseDao.findRelation(dishTagsEntityCollect);
//        Map<String, DishTagsEntity> foundRelations = relation.stream()
//                .collect(Collectors.toMap(
//                        entity -> entity.getDishId() + ":" + entity.getTagId(),
//                        entity -> entity));

        // 筛选出不存在于数据库中的菜标签关系对象集合
//        List<DishTagsEntity> result = dishTagsEntityCollect.stream()
//                .filter(entity -> foundRelations.containsKey(entity.getDishId() + ":" + entity.getTagId()))
//                .collect(Collectors.toList());
        // 删除菜单下的所有标签
        List<Long> dishIds = ListUtil.of(dishId);
        baseDao.deleteDishTagRelation(dishIds, null);
        // 批量插入新的菜标签关系
        baseDao.batchInsertDishTagRelation(dishTagsEntityCollect);

    }

    private boolean shouldUpdate(TagsDTO item) {
        return item.getTagId() != null;
    }
}